using System;
using System.Xml;

namespace Smart
{
	public static class ObjectExts
	{
		public static bool IsNull(this object value)
		{
			if (value == null || value is DBNull)
				return true;

			var res = false;
			var T = value.GetType();

			if (T == typeof(DateTime))
				res = ((DateTime)value) == DateTime.MinValue;
			else if (T == typeof(Guid))
				res = ((Guid)value) == Guid.Empty;
			else if (T == typeof(char))
				res = ((char)value) == '\0';

			return res;
		}

		public static bool IsNotNull(this object value)
		{
			if (value == null || value is DBNull)
				return false;

			var res = true;
			var T = value.GetType();

			if (T == typeof(DateTime))
				res = ((DateTime)value) != DateTime.MinValue;
			else if (T == typeof(Guid))
				res = ((Guid)value) != Guid.Empty;
			else if (T == typeof(char))
				res = ((char)value) != '\0';

			return res;
		}

		//public static string ToStr(this object value)
		//{
		//	return (value == null ? null : value.ToString());
		//}

		public static float CvtToFloat(this object value)
		{
			return Convert.ToSingle(value);
		}

		public static double CvtToDbl(this object value)
		{
			return Convert.ToDouble(value);
		}

		public static int CvtToInt(this object value)
		{
			return Convert.ToInt32(value);
		}

		public static long CvtToLong(this object value)
		{
			return Convert.ToInt64(value);
		}

		public static DateTime CvtToDT(this object value)
		{
			return Convert.ToDateTime(value);
		}

		/// <summary>
		/// Safe to string, default null
		/// </summary>
		public static string SToStr(this object value)
		{
			return SToStr(value, null);
		}

		/// <summary>
		/// Safe to string
		/// </summary>
		public static string SToStr(this object value, string nv)
		{
			return (value != null ? value.ToString() : nv);
		}

		/// <summary>
		/// Safe to int, default 0
		/// </summary>
		public static int SToInt(this object value)
		{
			return SToInt(value, 0);
		}

		/// <summary>
		/// Safe to int
		/// </summary>
		public static int SToInt(this object value, int nv)
		{
			var res = nv;

			if (value != null)
			{
				var svalue = value as string;
				if (svalue != null)
				{
					if (!int.TryParse(svalue, out res)) res = nv;
				}
				else if (value is Identifier)
				{
					return ((Identifier)value).Int;
				}
				else
				{
					try
					{
						res = Convert.ToInt32(value);
					}
					catch (Exception x)
					{
						H.LT("SToInt.Exception: can't parse '{0}' to 'int' type, exception message '{1}'", value, x.Message);

						res = nv;
					}
				}
			}

			return res;
		}

		/// <summary>
		/// Safe to long, default 0
		/// </summary>
		public static long SToLong(this object value)
		{
			return SToLong(value, 0);
		}

		/// <summary>
		/// Safe to long
		/// </summary>
		public static long SToLong(this object value, long nv)
		{
			var res = nv;

			if (value != null)
			{
				var svalue = value as string;
				if (svalue != null)
				{
					if (!long.TryParse(svalue, out res)) res = nv;
				}
				else
				{
					try
					{
						res = Convert.ToInt64(value);
					}
					catch (Exception x)
					{
						H.LT("SToLong.Exception: can't parse '{0}' to 'long' type, exception message '{1}'", value, x.Message);

						res = nv;
					}
				}
			}

			return res;
		}

		/// <summary>
		/// Safe to double, default 0
		/// </summary>
		public static double SToDbl(this object value)
		{
			return SToDbl(value, 0);
		}

		/// <summary>
		/// Safe to double
		/// </summary>
		public static double SToDbl(this object value, double nv)
		{
			var res = nv;

			if (value != null)
			{
				var svalue = value as string;
				if (svalue != null)
				{
					if (!double.TryParse(svalue, out res)) res = nv;
				}
				else
				{
					try
					{
						res = Convert.ToDouble(value);
					}
					catch (Exception x)
					{
						H.LT("SToDbl.Exception: can't parse '{0}' to 'double' type, exception message '{1}'", value, x.Message);

						res = nv;
					}
				}
			}

			return res;
		}

		/// <summary>
		/// Safe to bool, default false
		/// </summary>
		public static bool SToBool(this object value)
		{
			return SToBool(value, false);
		}

		/// <summary>
		/// Safe to bool
		/// </summary>
		public static bool SToBool(this object value, bool nv)
		{
			var res = nv;

			if (value != null)
			{
				var svalue = value as string;
				if (svalue != null)
				{
					if (!string.IsNullOrEmpty(svalue))
						if (!bool.TryParse(svalue, out res))
							res = nv;
				}
				else if (value is bool)
				{
					res = (bool)value;
				}
			}

			return res;
		}

		/// <summary>
		/// Safe to char, default '\x0'
		/// </summary>
		public static char SToChar(this object value)
		{
			return SToChar(value, '\x0');
		}

		/// <summary>
		/// Safe to char
		/// </summary>
		public static char SToChar(this object value, char nv)
		{
			var res = nv;

			if (value != null)
			{
				var svalue = value as string;
				if (svalue != null)
				{
					if (!string.IsNullOrEmpty(svalue))
						if (!char.TryParse(svalue.Substring(0, 1), out res))
							res = nv;
				}
				else if (value is char)
				{
					res = (char)value;
				}
			}

			return res;
		}

		/// <summary>
		/// Safe to Guid, default Guid.Empty
		/// </summary>
		public static Guid SToGuid(this object value)
		{
			return SToGuid(value, Guid.Empty);
		}

		/// <summary>
		/// Safe to Guid
		/// </summary>
		public static Guid SToGuid(this object value, Guid nv)
		{
			var res = nv;

			if (value != null)
			{
				var svalue = value as string;
				if (svalue != null)
				{
					try
					{
						res = (svalue.IsGuid() ? new Guid(svalue) : nv);
					}
					catch (Exception x)
					{
						H.LT("SToGuid.Exception: can't parse '{0}' to 'Guid' type, exception message '{1}'", svalue, x.Message);

						res = nv;
					}
				}
				else if (value is Guid)
				{
					res = (Guid)value;
				}
			}

			return res;
		}

		/// <summary>
		/// Safe to DateTime, default DateTime.MinValue
		/// </summary>
		public static DateTime SToDT(this object value)
		{
			return SToDT(value, DateTime.MinValue);
		}

		/// <summary>
		/// Safe to DateTime
		/// </summary>
		public static DateTime SToDT(this object value, DateTime nv)
		{
			var res = nv;

			if (value != null)
			{
				var svalue = value as string;
				if (svalue != null)
				{
					if (!string.IsNullOrEmpty(svalue))
					{
						var parsed = false;

						try
						{
							parsed = DateTime.TryParse(svalue, out res);
						}
						catch (Exception x)
						{
							H.LT("SToDT.Exception: can't parse '{0}' to 'DateTime' type, exception message '{1}'", svalue, x.Message);

							parsed = false;
						}

						if (!parsed)
							res = nv;
					}
				}
				else if (value is DateTime)
				{
					res = (DateTime)value;
				}
			}

			return res;
		}

		/// <summary>
		/// Safe to TimeSpan, default TimeSpan.MinValue
		/// </summary>
		public static TimeSpan SToTS(this object value)
		{
			return SToTS(value, TimeSpan.MinValue);
		}

		/// <summary>
		/// Safe to TimeSpan
		/// </summary>
		public static TimeSpan SToTS(this object value, TimeSpan nv)
		{
			var res = nv;

			if (value != null)
			{
				var svalue = value as string;
				if (svalue != null)
				{
					if (!string.IsNullOrEmpty(svalue))
					{
						var parsed = false;

						try
						{
							parsed = TimeSpan.TryParse(svalue, out res);
						}
						catch (Exception x)
						{
							H.LT("SToTS.Exception: can't parse '{0}' to 'TimeSpan' type, exception message '{1}'", svalue, x.Message);

							parsed = false;
						}

						if (!parsed)
							res = nv;
					}
				}
				else if (value is TimeSpan)
				{
					res = (TimeSpan)value;
				}
			}

			return res;
		}

		/// <summary>
		/// Parse xml duration
		/// </summary>
		public static TimeSpan ParseXmlDuration(this string xml, TimeSpan defaultValue)
		{
			try
			{
				return xml.IsNullOrEmpty() ? defaultValue : XmlConvert.ToTimeSpan(xml);
			}
			catch
			{
				return defaultValue;
			}
		}

		/// <summary>
		/// Safe to Enum, default default(TEnumType)
		/// </summary>
		public static TEnumType SToE<TEnumType>(this object value)
		{
			return SToE(value, default(TEnumType));
		}

		/// <summary>
		/// Safe to Enum
		/// </summary>
		public static TEnumType SToE<TEnumType>(this object value, TEnumType nv)
		{
			var res = nv;

			if (value != null)
			{
				var svalue = value as string;
				if (svalue != null)
				{
					if (!string.IsNullOrEmpty(svalue))
					{
						bool parsed;

						try
						{
							res = (TEnumType)Enum.Parse(typeof(TEnumType), svalue, true);

							parsed = true;
						}
						catch (Exception x)
						{
							H.LT("SToE.Exception: can't parse '{0}' to '{1}' type, exception message '{2}'", svalue, typeof(TEnumType).Name, x.Message);

							parsed = false;
						}

						if (!parsed)
							res = nv;
					}
				}
				else if (value is TEnumType)
				{
					res = (TEnumType)value;
				}
				else if (value is int)
				{
					bool parsed;

					try
					{
						res = (TEnumType)Enum.ToObject(typeof(TEnumType), (int)value);

						parsed = true;
					}
					catch (Exception x)
					{
						H.LT("SToE.Exception: can't parse '{0}' to '{1}' type, exception message '{2}'", value, typeof(TEnumType).Name, x.Message);

						parsed = false;
					}

					if (!parsed)
						res = nv;
				}
			}

			return res;
		}
	}
}
